package com.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 重点：自定义分页
 */
public class Pagination {
    // 页码（从 1 开始）
    private int pageNo = 1;
    // 总记录数量（默认为 0）
    private int recordCount = 0;
    // 每页的记录数量（默认为 2）
    private int pageSize = 2;

    // 总的页数，比如 7 条记录，每页 2 条记录就等于 4，如果是 6 条记录就等于 3（默认为 0）
    private int pages = 0;
    // 指的是首页（默认为 1）之后有多少个数字，比如值是 2，就表示要生成 2 个数，分别是 2, 3
    private int firstCount = 2;
    // 表示尾页左边有多少个数，比如尾页是 50，值为 2，就表示要生成 48, 49 这 2 个数，
    // 如果值为 3 的话，就表示要生成 47, 48, 49 这 3 个数
    private int lastCount = 2;

    // 当前页左边数字的数量，比如当前页是 12，值为 3 的话就表示要生成 9, 10, 11 这 3 个数
    private int currentLeftCount = 3;
    // 当前页右边数字的数量，比如当前页是 12，值为 3 的话就表示要生成 13, 14, 15 这 3 个数
    private int currentRightCount = 3;
    // 分页栏中带三个省略号
    private String ellipsis = "...";

    // 无参构造函数（但是有默认的值）
    public Pagination() {
        this(1, 0, 2);
    }

    // 带参构造（先写带参构造上面的无参构造才能赋值）
    public Pagination(int pageNo, int recordCount, int pageSize) {
        this.pageNo = pageNo;
        this.recordCount = recordCount;
        this.pageSize = pageSize;

        // 计算总页数（使用总记录数除以每页的记录数就能计算出总页数）
        this.pages = (int) Math.ceil(this.recordCount * 1.0 / this.pageSize);
    }

    // get 方法
    // 获取页码值
    public int getPageNo() {
        return pageNo;
    }

    // 获取每页记录数量值
    public int getPageSize() {
        return pageSize;
    }

    // 获取首页值
    public int getFirst() {
        return 1;
    }

    // 获取最后一页值
    public int getLast() {
        // ceil 是获取大于等于某个数的最小整数，比如 3.5，大于它的数有 4, 5, 6
        return this.pages;
    }

    // 获取上一页值
    public int getPrev() {
        return Math.max(this.pageNo - 1, 1);
    }

    // 获取下一页值
    public int getNext() {
        return Math.min(this.pageNo + 1, this.pages);
    }

    // 获取省略号
    public String getEllipsis() {
        return ellipsis;
    }

    // set 方法
    // 设置首页值
    public void setFirstCount(int firstCount) {
        this.firstCount = firstCount;
    }

    // 设置尾页左边的值
    public void setLastCount(int lastCount) {
        this.lastCount = lastCount;
    }

    // 设置省略号值
    public void setEllipsis(String ellipsis) {
        this.ellipsis = ellipsis;
    }

    // 设置当前页左侧数量的值
    public void setCurrentLeftCount(int currentLeftCount) {
        this.currentLeftCount = currentLeftCount;
    }

    // 设置当前页右侧数量的值
    public void setCurrentRightCount(int currentRightCount) {
        this.currentRightCount = currentRightCount;
    }

    public List<Integer> generateNums2() {
        // 首页的数字范围
        IntStream firstRange = IntStream.range(1, 1 + firstCount + 1);
        // 当前页左边的数字（不包含当前页）
        IntStream currentLeftRange = IntStream.range(pageNo - currentLeftCount, pageNo);
        // 当前页 + 当前页右边的数字
        IntStream currentRightRange = IntStream.range(pageNo, pageNo + currentRightCount + 1);
        // 尾页左边的数字 + 尾页
        IntStream lastRange = IntStream.range(this.pages - lastCount, this.pages + 1);

        // 合并生成 4 组数字
        Stream<IntStream> allRange = Stream.of(firstRange, currentLeftRange, currentRightRange, lastRange);
        // 剔除越界的数字
        IntStream allRangeFlatted = allRange.flatMapToInt(x -> x)
                .filter(n -> n >= 1 && n <= this.pages);

        // 剔除重复
        Stream<Integer> distinctRange = allRangeFlatted.distinct().boxed();

        List<Integer> result = distinctRange.collect(Collectors.toList());
        return result;
    }

    // 建议用下面的写法，完全跟上面一样，只不过是一行搞定
    public List<Integer> generateNums() {
        return Stream.of(IntStream.range(1, 1 + firstCount + 1)
                , IntStream.range(pageNo - currentLeftCount, pageNo)
                , IntStream.range(pageNo, pageNo + currentRightCount + 1)
                , IntStream.range(this.pages - lastCount, this.pages + 1))
                // 这里得到的是 IntStream 流
                .flatMapToInt(x -> x)
                .filter(n -> n >= 1 && n <= pages)
                .distinct()
                // 为了把 IntStream 转换成 Stream<Integer>，更好的使用 .collect(Collectors.toList())
                .boxed()
                .collect(Collectors.toList());
    }

    // 获取数字文本
    public List<String> getNumText() {
        List<String> result = new ArrayList<>();
        List<Integer> nums = generateNums();
        for (int i = 0; i < nums.size(); i++) {
            int currentNum = nums.get(i);
            result.add(currentNum + "");
            if ((i + 1) < nums.size()) {
                int nextNum = nums.get(i + 1);
                if (nextNum - currentNum > 1) {
                    result.add(ellipsis);
                }
            }
        }
        return result;
    }

    // 测试方法
    public static void main(String[] args) {
        // 一共有 10 条记录，每页三条记录，可以分 4 页
        Pagination pagination = new Pagination(2, 10, 3);
        List<String> numText = pagination.getNumText();
        numText.forEach(System.out::println);
    }
}
